<!DOCTYPE html>
<html  lang="zh">
<head>
    <meta charset="utf-8">
<title>3. SPI框架实现之旅三：实现说明 - 一灰灰Blog</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />



    <meta name="description" content="实现说明 前一篇 《SPI框架实现之旅二：整体设计》中，介绍了几个定义的接口，注解；叙述了实现流程；并简单的介绍了 SpiLoader中的部分实现； 本篇则主要介绍SpiLoader类的实现  类图结构如下：">
<meta name="keywords" content="Java,技术方案">
<meta property="og:type" content="article">
<meta property="og:title" content="3. SPI框架实现之旅三：实现说明">
<meta property="og:url" content="https://blog.hhui.top/hexblog/2017/05/29/SPI框架实现之旅三：实现说明/index.html">
<meta property="og:site_name" content="一灰灰Blog">
<meta property="og:description" content="实现说明 前一篇 《SPI框架实现之旅二：整体设计》中，介绍了几个定义的接口，注解；叙述了实现流程；并简单的介绍了 SpiLoader中的部分实现； 本篇则主要介绍SpiLoader类的实现  类图结构如下：">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://blog.hhui.top/hexblog/images/og_image.png">
<meta property="og:updated_time" content="2018-07-25T14:55:41.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="3. SPI框架实现之旅三：实现说明">
<meta name="twitter:description" content="实现说明 前一篇 《SPI框架实现之旅二：整体设计》中，介绍了几个定义的接口，注解；叙述了实现流程；并简单的介绍了 SpiLoader中的部分实现； 本篇则主要介绍SpiLoader类的实现  类图结构如下：">
<meta name="twitter:image" content="https://blog.hhui.top/hexblog/images/og_image.png">







<link rel="icon" href="/hexblog/images/avatar.jpg">


<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.7.2/css/bulma.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:400,600|Source+Code+Pro">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@9.12.0/styles/docco.css">


    
    
    
    <style>body>.footer,body>.navbar,body>.section{opacity:0}</style>
    

    
    
    
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lightgallery@1.6.8/dist/css/lightgallery.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/css/justifiedGallery.min.css">
    

    
    

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.css">


    
    
    
    

<link rel="stylesheet" href="/hexblog/css/back-to-top.css">


    
    

    
    
<script>
var _hmt = _hmt || [];
(function() {
    var hm = document.createElement("script");
    hm.src = "//hm.baidu.com/hm.js?028d9e53f991d9739ecc7cc42e13c500";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
})();
</script>

    
    

    
    
<link rel="stylesheet" href="/hexblog/css/progressbar.css">
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

    
    
    

    
    
    


<link rel="stylesheet" href="/hexblog/css/style.css">
</head>
<body class="is-3-column">
    <nav class="navbar navbar-main">
    <div class="container">
        <div class="navbar-brand is-flex-center">
            <a class="navbar-item navbar-logo" href="/hexblog/">
            
                <img src="/hexblog/images/avatar.jpg" alt="3. SPI框架实现之旅三：实现说明" height="28">
            
            </a>
        </div>
        <div class="navbar-menu">
            
            <div class="navbar-start">
                
                <a class="navbar-item"
                href="/hexblog/.">首页</a>
                
                <a class="navbar-item"
                href="/hexblog/archives">归档</a>
                
                <a class="navbar-item"
                href="/hexblog/tags">标签</a>
                
                <a class="navbar-item"
                href="http://spring.hhui.top">Spring</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/Java/">Java</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/Python/">Python</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/DB/">DB</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/Shell/">Shell</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/Quick系列/">Quick系列</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/前端/">前端</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/开源/">开源</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/工具/">工具</a>
                
                <a class="navbar-item"
                href="/hexblog/categories/随笔/">随笔</a>
                
                <a class="navbar-item"
                href="/hexblog/about">关于</a>
                
            </div>
            
            <div class="navbar-end">
                
                    
                    
                    <a class="navbar-item" target="_blank" title="Download on GitHub" href="https://github.com/liuyueyi">
                        
                        <i class="fab fa-github"></i>
                        
                    </a>
                    
                
                
                
                <a class="navbar-item search" title="搜索" href="javascript:;">
                    <i class="fas fa-search"></i>
                </a>
                
            </div>
        </div>
    </div>
</nav>
    
    <section class="section">
        <div class="container">
            <div class="columns">
                <div class="column is-8-tablet is-8-desktop is-7-widescreen has-order-2 column-main"><div class="card">
    
        <span >
            <div class="thumbnail default_logo">
                <br/>
                <span >
                3. SPI框架实现之旅三：实现说明
                <br>
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                <span style="font-size:0.7em">by 一灰灰</span>
                </span>
            </div>
            </span>
    

    <div class="card-content article ">
        
        <div class="level article-meta is-size-7 is-uppercase is-mobile is-overflow-x-auto">
            <div class="level-left">
                <time class="level-item has-text-grey" datetime="2017-05-29T02:50:37.000Z">2017-05-29</time>
                
                <div class="level-item">
                <a class="has-link-black -link" href="/hexblog/categories/Quick系列/">Quick系列</a>&nbsp;/&nbsp;<a class="has-link-black -link" href="/hexblog/categories/Quick系列/QuickSpi/">QuickSpi</a>
                </div>
                
                
                <span class="level-item has-text-grey" style='font-size: 1.2em;'>
                    
                    
                    30 分钟 读完 (大约 4570 个字)
                </span>
                
                
                
                <span class="level-item has-text-grey" id="busuanzi_container_page_pv">
                    <i class="far fa-eye"></i>
                    <span id="busuanzi_value_page_pv">0</span>次访问
                </span>
                
            </div>
        </div>
        
        <h1 class="title is-size-3 is-size-4-mobile has-text-weight-normal">
            
                3. SPI框架实现之旅三：实现说明
            
        </h1>
        <div class="content">
            
                <!-- 文章详情页 -->
                <div id="toc" class="toc-article">
                <strong class="toc-title"> 文章目录 </strong>
                    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#实现说明"><span class="toc-text">实现说明</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#SpiLoader-全解析"><span class="toc-text">SpiLoader 全解析</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-获取spiLoader对象"><span class="toc-text">1. 获取spiLoader对象</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#实现"><span class="toc-text">实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#说明"><span class="toc-text">说明</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-新建-SpiLoader对象"><span class="toc-text">2. 新建 SpiLoader对象</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#实现-1"><span class="toc-text">实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#说明-1"><span class="toc-text">说明</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-静态使用"><span class="toc-text">3. 静态使用</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#实现-2"><span class="toc-text">实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#说明-2"><span class="toc-text">说明</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-动态使用"><span class="toc-text">4. 动态使用</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#设计的出发点"><span class="toc-text">设计的出发点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#实现如下"><span class="toc-text">实现如下</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#说明-3"><span class="toc-text">说明</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-spi实现类映射关系表初始化"><span class="toc-text">5. spi实现类映射关系表初始化</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#缓存结构"><span class="toc-text">缓存结构</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#实现-3"><span class="toc-text">实现</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#说明-4"><span class="toc-text">说明</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#动态代码生成"><span class="toc-text">动态代码生成</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-代理类格式"><span class="toc-text">1. 代理类格式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#代理类生成"><span class="toc-text">代理类生成</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#动态编译运行"><span class="toc-text">动态编译运行</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#小结"><span class="toc-text">小结</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#博客系列链接："><span class="toc-text">博客系列链接：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#项目-QuickAlarm"><span class="toc-text">项目: QuickAlarm</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#个人博客：-Z-blog"><span class="toc-text">个人博客： Z+|blog</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#声明"><span class="toc-text">声明</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#扫描关注"><span class="toc-text">扫描关注</span></a></li></ol></li></ol></li></ol>
                </div>
            

            <h1 id="实现说明"><a href="#实现说明" class="headerlink" title="实现说明"></a>实现说明</h1><blockquote>
<p>前一篇 《SPI框架实现之旅二：整体设计》中，介绍了几个定义的接口，注解；叙述了实现流程；并简单的介绍了 <code>SpiLoader</code>中的部分实现； 本篇则主要介绍<code>SpiLoader</code>类的实现</p>
</blockquote>
<p>类图结构如下：</p>
<p><img src="https://static.oschina.net/uploads/img/201705/27183336_TOny.png" alt="https://static.oschina.net/uploads/img/201705/27183336_TOny.png"></p>
<a id="more"></a>
<h2 id="SpiLoader-全解析"><a href="#SpiLoader-全解析" class="headerlink" title="SpiLoader 全解析"></a>SpiLoader 全解析</h2><blockquote>
<p>spiImpl选择的核心类，包括初始化选择器，初始化spiImpl实现列表，解析spiImpl的选择条件，返回具体的实现类等</p>
</blockquote>
<h3 id="1-获取spiLoader对象"><a href="#1-获取spiLoader对象" class="headerlink" title="1. 获取spiLoader对象"></a>1. 获取spiLoader对象</h3><blockquote>
<p><code>SpiLoader</code> 是一个泛型对象，每个SPI接口，对应一个<code>SpiLoader&lt;T&gt;</code> 对象，我们提供了一个静态方法来获取这个对象</p>
</blockquote>
<h4 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h4><p>优先从缓存中获取， 如果缓存没有，则新建一个；缓存中有， 则直接返回</p>
<figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">* spiLoader缓存, 其中key为 spi接口, value为对应的Loader对象</span></span><br><span class="line"><span class="hljs-comment">*/</span></span><br><span class="line"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> ConcurrentMap&lt;Class&lt;?&gt;, SpiLoader&lt;?&gt;&gt; loaderCache = <span class="hljs-keyword">new</span> ConcurrentHashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">"unchecked"</span>)</span><br><span class="line"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> &lt;T&gt; <span class="hljs-function">SpiLoader&lt;T&gt; <span class="hljs-title">load</span><span class="hljs-params">(Class&lt;T&gt; type)</span> </span>&#123;</span><br><span class="line">   <span class="hljs-keyword">if</span> (<span class="hljs-keyword">null</span> == type) &#123;</span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"common cannot be null..."</span>);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">if</span> (!type.isInterface()) &#123;</span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"common class:"</span> + type + <span class="hljs-string">" must be interface!"</span>);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">if</span> (!withSpiAnnotation(type)) &#123;</span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"common class:"</span> + type + <span class="hljs-string">" must have the annotation of @Spi"</span>);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   SpiLoader&lt;T&gt; spiLoader = (SpiLoader&lt;T&gt;) loaderCache.get(type);</span><br><span class="line">   <span class="hljs-keyword">if</span> (spiLoader == <span class="hljs-keyword">null</span>) &#123;</span><br><span class="line">       loaderCache.putIfAbsent(type, <span class="hljs-keyword">new</span> SpiLoader&lt;&gt;(type));</span><br><span class="line">       spiLoader = (SpiLoader&lt;T&gt;) loaderCache.get(type);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">return</span> spiLoader;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h4><ul>
<li>上面有几个校验，前一篇已经说明，不再赘述</li>
<li>上面新建对象，不是线程安全的</li>
</ul>
<h3 id="2-新建-SpiLoader对象"><a href="#2-新建-SpiLoader对象" class="headerlink" title="2. 新建 SpiLoader对象"></a>2. 新建 <code>SpiLoader</code>对象</h3><blockquote>
<p>创建对象，主要会初始化选择器</p>
</blockquote>
<h4 id="实现-1"><a href="#实现-1" class="headerlink" title="实现"></a>实现</h4><figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">SpiLoader</span><span class="hljs-params">(Class&lt;T&gt; type)</span> </span>&#123;</span><br><span class="line">   <span class="hljs-comment">// 初始化默认的选择器, 为保留项目, 必然会提供的服务</span></span><br><span class="line">   selectorInstanceCacheMap.putIfAbsent(DefaultSelector.class, DEFAULT_SELECTOR);</span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">this</span>.spiInterfaceType = type;</span><br><span class="line">   initSelector();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initSelector</span><span class="hljs-params">()</span> </span>&#123;</span><br><span class="line">   Spi ano = spiInterfaceType.getAnnotation(Spi.class);</span><br><span class="line">   <span class="hljs-keyword">if</span> (ano == <span class="hljs-keyword">null</span>) &#123;</span><br><span class="line">       currentSelector = initSelector(DefaultSelector.class);</span><br><span class="line">   &#125; <span class="hljs-keyword">else</span> &#123;</span><br><span class="line">       currentSelector = initSelector(ano.selector());</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   Method[] methods = <span class="hljs-keyword">this</span>.spiInterfaceType.getMethods();</span><br><span class="line">   currentMethodSelector = <span class="hljs-keyword">new</span> ConcurrentHashMap&lt;&gt;();</span><br><span class="line">   SelectorWrapper temp;</span><br><span class="line">   <span class="hljs-keyword">for</span> (Method method : methods) &#123;</span><br><span class="line">       <span class="hljs-keyword">if</span> (!method.isAnnotationPresent(SpiAdaptive.class)) &#123;</span><br><span class="line">           <span class="hljs-keyword">continue</span>;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       temp = initSelector(method.getAnnotation(SpiAdaptive.class).selector());</span><br><span class="line">       <span class="hljs-keyword">if</span> (temp == <span class="hljs-keyword">null</span>) &#123;</span><br><span class="line">           <span class="hljs-keyword">continue</span>;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       currentMethodSelector.put(method.getName(), temp);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">private</span> SelectorWrapper <span class="hljs-title">initSelector</span><span class="hljs-params">(Class&lt;? extends ISelector&gt; clz)</span> </span>&#123;</span><br><span class="line">   <span class="hljs-comment">// 优先从选择器缓存中获取类型对应的选择器</span></span><br><span class="line">   <span class="hljs-keyword">if</span> (selectorInstanceCacheMap.containsKey(clz)) &#123;</span><br><span class="line">       <span class="hljs-keyword">return</span> selectorInstanceCacheMap.get(clz);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">try</span> &#123;</span><br><span class="line">       ISelector selector = clz.newInstance();</span><br><span class="line">       Class paramClz = <span class="hljs-keyword">null</span>;</span><br><span class="line"></span><br><span class="line">       Type[] types = clz.getGenericInterfaces();</span><br><span class="line">       <span class="hljs-keyword">for</span> (Type t : types) &#123;</span><br><span class="line">           <span class="hljs-keyword">if</span> (t <span class="hljs-keyword">instanceof</span> ParameterizedType) &#123;</span><br><span class="line">               paramClz = (Class) ((ParameterizedType) t).getActualTypeArguments()[<span class="hljs-number">0</span>];</span><br><span class="line">               <span class="hljs-keyword">break</span>;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       Assert.check(paramClz != <span class="hljs-keyword">null</span>);</span><br><span class="line">       SelectorWrapper wrapper = <span class="hljs-keyword">new</span> SelectorWrapper(selector, paramClz);</span><br><span class="line">       selectorInstanceCacheMap.putIfAbsent(clz, wrapper);</span><br><span class="line">       <span class="hljs-keyword">return</span> wrapper;</span><br><span class="line">   &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;</span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"illegal selector defined! yous:"</span> + clz);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="说明-1"><a href="#说明-1" class="headerlink" title="说明"></a>说明</h4><ul>
<li>持有一个选择器缓存列表，<code>selectorInstanceCacheMap</code><ul>
<li>保证每种类型的选择器，在这个SpiLoader中，只会有一个实例存在</li>
<li>不做成全局唯一的原因是尽量隔离, 比如  <code>ParamsSelector</code> 内部缓存了spi实现的列表，如果全局公用的话，就会混掉，导致这个列表中就出现非这个spi接口的实现类</li>
</ul>
</li>
<li>类选择器 + 方法选择器<ul>
<li><code>currentSelector</code> ： 类选择器, 解析 <code>@Spi</code> 注解获取，适用于静态选择 + 动态选择两种使用方式</li>
<li><code>currentMethodSelector</code> : 方法选择器，解析 <code>@SpiAdaptive</code> 注解获取， 仅适用于动态选择SPI实现的方式</li>
<li>优先级： 方法上定义的选择器 由于  类上定义的选择器； 方法上未定义时，默认使用类定义的选择器</li>
</ul>
</li>
</ul>
<h3 id="3-静态使用"><a href="#3-静态使用" class="headerlink" title="3. 静态使用"></a>3. 静态使用</h3><blockquote>
<p>静态使用方式，表示根据传入的条件，选择一个满足条件的实现返回</p>
</blockquote>
<h4 id="实现-2"><a href="#实现-2" class="headerlink" title="实现"></a>实现</h4><figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">* 根据传入条件, 选择具体的spi实现类</span></span><br><span class="line"><span class="hljs-comment">* &lt;p/&gt;</span></span><br><span class="line"><span class="hljs-comment">* 这里要求conf的类型和选择器的参数类型匹配, 否则会尝试使用默认的选择器补救, 若补救失败, 则抛异常</span></span><br><span class="line"><span class="hljs-comment">*</span></span><br><span class="line"><span class="hljs-comment">* <span class="hljs-doctag">@param</span> conf</span></span><br><span class="line"><span class="hljs-comment">* <span class="hljs-doctag">@return</span></span></span><br><span class="line"><span class="hljs-comment">* <span class="hljs-doctag">@throws</span> NoSpiMatchException</span></span><br><span class="line"><span class="hljs-comment">* <span class="hljs-doctag">@throws</span> IllegalArgumentException</span></span><br><span class="line"><span class="hljs-comment">*/</span></span><br><span class="line"><span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">"unchecked"</span>)</span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">public</span> T <span class="hljs-title">getService</span><span class="hljs-params">(Object conf)</span> <span class="hljs-keyword">throws</span> NoSpiMatchException </span>&#123;</span><br><span class="line">   <span class="hljs-keyword">if</span> (spiImplClassCacheMap == <span class="hljs-keyword">null</span> || spiImplClassCacheMap.size() == <span class="hljs-number">0</span>) &#123;</span><br><span class="line">       loadSpiService();</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">if</span> (!currentSelector.getConditionType().isAssignableFrom(conf.getClass())) &#123;</span><br><span class="line"></span><br><span class="line">       <span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">        * 参数类型不匹配时, 判断是否可以根据默认的选择器来获取</span></span><br><span class="line"><span class="hljs-comment">        */</span></span><br><span class="line">       <span class="hljs-keyword">if</span> (conf <span class="hljs-keyword">instanceof</span> String) &#123;</span><br><span class="line">           <span class="hljs-keyword">return</span> (T) DEFAULT_SELECTOR.getSelector().selector(spiImplClassCacheMap, conf);</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">       <span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">        * 参数类型完全不匹配, 则抛参数异常</span></span><br><span class="line"><span class="hljs-comment">        */</span></span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"conf spiInterfaceType should be sub class of ["</span> + currentSelector.getConditionType() + <span class="hljs-string">"] but yours:"</span> + conf.getClass());</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">return</span> (T) currentSelector.getSelector().selector(spiImplClassCacheMap, conf);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="说明-2"><a href="#说明-2" class="headerlink" title="说明"></a>说明</h4><ol>
<li><p><code>spiImplClassCacheMap</code> </p>
<p> spi实现的缓存映射表，优先判断缓存映射表是否存在，不存在时需要初始化；存在时，则进入校验逻辑</p>
</li>
<li><p>校验</p>
<p>校验传入的参数，是否匹配当前的选择器参数类型，为了保证选择器可以正常运行</p>
<p>当不匹配时，会有一个兼容逻辑，判断传参类型是否为String， 是则采用默认的选择器，根据name来选择spi实现 （这种实现可能造成选择的实现不是预期的）</p>
</li>
<li><p>静态使用方式，使用类定义选择器 : <code>currentSelector</code></p>
<ul>
<li><p>静态使用的方式，目标就是事前就确认使用这个实现了，不会出现变动了； 相当于一次确认，所有的调用都是确认的</p>
</li>
<li><p>静态使用，方法注解的选择器无效。这个我们从逆向的思路进行解释</p>
<pre><code>IPrint 是一个Spi接口， 有两个实现   FilePrint,   ConsolePrint
假设 `currentSelector=DefaultSelector`， 方法  methodA 上定义的是  ParamsSelector 时

静态使用方式，获取一个spi实现，希望在所有的spi接口使用处，都输出到文件，用户根据 `FilePrint` 选择  FilePrint 这个类来执行具体的输出逻辑， 如果在调用 methodA 方法执行时， 假设根据  ParamsSelector 判断， ConsolePrint 才满足这儿条件，这是相当于在具体实现时，换成了另一个 ConsolePrint, 这下子就与我们的初衷背离了（如果目标是想实现这个场景，显然动态适配的方式才是正确的使用姿势）
</code></pre></li>
</ul>
</li>
<li><p>loadService 的逻辑后面详细说明</p>
</li>
</ol>
<h3 id="4-动态使用"><a href="#4-动态使用" class="headerlink" title="4. 动态使用"></a>4. 动态使用</h3><blockquote>
<p>动态使用区别于静态的直接确定实现类， 通过<code>getService</code> 获取的并不是某个特定对的实现类，而是一个动态生成的代理，每次具体执行之前，会去判断一下，应该选择哪一个实现来执行</p>
</blockquote>
<h4 id="设计的出发点"><a href="#设计的出发点" class="headerlink" title="设计的出发点"></a>设计的出发点</h4><p>可以考虑下，我们的目标是在执行方法之前，需要判断一下哪个实现类满足要求，选择这个实现类来执行这个方法，那么我们可以怎么去做？</p>
<p>考虑到切面的方式，如果有一种手段，在方法执行之前，织入一段业务逻辑，就可以达到上面的目的</p>
<p>最开始虽然是怎么想的，但是有点尴尬的是，不知道怎么去实现；因此换了一个思路，我自己新生成一个接口的实现类，在这个实现类里面做选择逻辑，然后把这个实现类对象返回</p>
<h4 id="实现如下"><a href="#实现如下" class="headerlink" title="实现如下"></a>实现如下</h4><p>和静态实现的逻辑差不多，一般流程如下:</p>
<ul>
<li>判断spi实现类的映射关系表是否初始化，若没有则初始化</li>
<li>获取选择器<ul>
<li>优先从方法选择器中查找， 若存在，则直接选中；</li>
<li>不存在，则使用类选择器</li>
</ul>
</li>
<li>校验：判断传入条件参数类型是否满足选择器的参数类型匹配（将方法的第一个参数，作为选择器的选择条件）</li>
<li>返回实现类</li>
</ul>
<figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">"unchecked"</span>)</span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">public</span> T <span class="hljs-title">getService</span><span class="hljs-params">(Object conf, String methodName)</span> <span class="hljs-keyword">throws</span> NoSpiMatchException </span>&#123;</span><br><span class="line">   <span class="hljs-keyword">if</span> (spiImplClassCacheMap == <span class="hljs-keyword">null</span> || spiImplClassCacheMap.size() == <span class="hljs-number">0</span>) &#123;</span><br><span class="line">       loadSpiService();</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-comment">// 首先获取对应的selector</span></span><br><span class="line">   SelectorWrapper selector = currentMethodSelector.get(methodName);</span><br><span class="line">   <span class="hljs-keyword">if</span> (selector == <span class="hljs-keyword">null</span>) &#123; <span class="hljs-comment">// 自适应方法上未定义选择器, 则默认继承类的</span></span><br><span class="line">       selector = currentSelector;</span><br><span class="line">       currentMethodSelector.putIfAbsent(methodName, selector);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">if</span> (!selector.getConditionType().isAssignableFrom(conf.getClass())) &#123; <span class="hljs-comment">// 选择器类型校验</span></span><br><span class="line">       <span class="hljs-keyword">if</span> (!(conf <span class="hljs-keyword">instanceof</span> String)) &#123;</span><br><span class="line">           <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"conf spiInterfaceType should be sub class of ["</span> + currentSelector.getConditionType() + <span class="hljs-string">"] but yours:"</span> + conf.getClass());</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">       selector = DEFAULT_SELECTOR;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">if</span> (spiImplMethodCacheMap.size() == <span class="hljs-number">0</span>) &#123;</span><br><span class="line">       <span class="hljs-keyword">return</span> (T) selector.getSelector().selector(spiImplClassCacheMap, conf);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">try</span> &#123;</span><br><span class="line">       <span class="hljs-comment">// 采用默认的选择器,根据指定name 进行查询时, 需要兼容一下, 因为method对应的缓存key为  SpiImpName_methodName</span></span><br><span class="line">       <span class="hljs-keyword">if</span> (DEFAULT_SELECTOR.equals(selector)) &#123;</span><br><span class="line">           <span class="hljs-keyword">if</span> (spiImplMethodCacheMap.containsKey(conf)) &#123;</span><br><span class="line">               <span class="hljs-keyword">return</span> (T) selector.getSelector().selector(spiImplMethodCacheMap, conf);</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           <span class="hljs-keyword">if</span> (spiImplClassCacheMap.containsKey(conf)) &#123;</span><br><span class="line">               <span class="hljs-keyword">return</span> (T) selector.getSelector().selector(spiImplClassCacheMap, conf);</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           <span class="hljs-keyword">return</span> (T) selector.getSelector().selector(spiImplMethodCacheMap, conf + <span class="hljs-string">"_"</span> + methodName);</span><br><span class="line">       &#125; <span class="hljs-keyword">else</span> &#123;</span><br><span class="line">           <span class="hljs-keyword">return</span> (T) selector.getSelector().selector(spiImplMethodCacheMap, conf);</span><br><span class="line">       &#125;</span><br><span class="line">   &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;</span><br><span class="line">       <span class="hljs-keyword">return</span> (T) selector.getSelector().selector(spiImplClassCacheMap, conf);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="说明-3"><a href="#说明-3" class="headerlink" title="说明"></a>说明</h4><ol>
<li>这个方法通常是由框架生成的代理实现类来调用（后面会说明动态生成代理类的逻辑）</li>
<li>区别与静态使用方式， 优先根据方法名，查找对应的选择器；当未定义时，使用类选择器</li>
<li><p>默认选择器，根据name来查询实现时，传入的参数特殊处理下，主要是因为 <code>spiImplMethodCacheMap</code> 中key的生成，有一个小转换</p>
<pre><code>若实现类上没有 @SpiConf注解，或者 @SpiConf的注解没有定义 name 属性，则类的唯一标识name为：简单类名； 否则为指定的name属性

若方法上显示使用 @SpiConf 指定了name属性，则key的生成规则为： 方法注解上指定的name； 
如果没有 @SpiConf注解，或其中没有指定name属性，则key生成规则:  类name属性 + 下划线 + 方法名
</code></pre><p> 这一点单独看可能不太好理解，因此可以和下面的spi实现类映射关系的初始化结合起来</p>
</li>
<li><p>动态生成代理类的逻辑，放在最后进行说明</p>
</li>
</ol>
<h3 id="5-spi实现类映射关系表初始化"><a href="#5-spi实现类映射关系表初始化" class="headerlink" title="5. spi实现类映射关系表初始化"></a>5. spi实现类映射关系表初始化</h3><blockquote>
<p>为了避免每次选择具体的实现类时，都去加载一遍，耗时耗力好性能，因此加一个缓存是很有必要的，这里主要说下这个实现逻辑，以及为啥这么干</p>
</blockquote>
<h4 id="缓存结构"><a href="#缓存结构" class="headerlink" title="缓存结构"></a>缓存结构</h4><p>使用了两个Map：</p>
<ul>
<li>一个是类级别的映射关系 <code>spiImplClassCacheMap</code><ul>
<li>静态使用时，只会用搞这个</li>
<li>动态适配时，当下面的映射关系中无法获取满足条件的实现时，会再次从这里进行判断</li>
<li>key：  <code>@SpiConf</code> 注解中定义的name； 或者spi实现类的简单类名</li>
</ul>
</li>
<li>一个是方法的映射关系 <code>spiImplMethodCacheMap</code><ul>
<li>动态适配时， 选择器优先从这里进行判断</li>
<li>key:   <code>@SpiConf</code> 注解中定义的name； 或者是 实现类的 name + “_” + 方法名</li>
</ul>
</li>
</ul>
<figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">* name : spiImpl 的映射表</span></span><br><span class="line"><span class="hljs-comment">*/</span></span><br><span class="line"><span class="hljs-keyword">private</span> Map&lt;String, SpiImplWrapper&lt;T&gt;&gt; spiImplClassCacheMap;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">* 自适应时, 根据方法选择实现; name : spiImpl 的映射表</span></span><br><span class="line"><span class="hljs-comment">*/</span></span><br><span class="line"><span class="hljs-keyword">private</span> Map&lt;String, SpiImplWrapper&lt;T&gt;&gt; spiImplMethodCacheMap;</span><br></pre></td></tr></table></figure>
<h4 id="实现-3"><a href="#实现-3" class="headerlink" title="实现"></a>实现</h4><figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">loadSpiService</span><span class="hljs-params">()</span> </span>&#123;</span><br><span class="line">   List&lt;SpiImplWrapper&lt;T&gt;&gt; spiServiceList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">   List&lt;SpiImplWrapper&lt;T&gt;&gt; spiServiceMethodList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">   ServiceLoader&lt;T&gt; serviceLoader = ServiceLoader.load(spiInterfaceType);</span><br><span class="line"></span><br><span class="line">   SpiConf spiConf;</span><br><span class="line">   String implName;</span><br><span class="line">   <span class="hljs-keyword">int</span> implOrder;</span><br><span class="line">   <span class="hljs-keyword">for</span> (T t : serviceLoader) &#123;</span><br><span class="line">       spiConf = t.getClass().getAnnotation(SpiConf.class);</span><br><span class="line">       Map&lt;String, String&gt; map;</span><br><span class="line">       <span class="hljs-keyword">if</span> (spiConf == <span class="hljs-keyword">null</span>) &#123;</span><br><span class="line">           implName = t.getClass().getSimpleName();</span><br><span class="line">           implOrder = SpiImplWrapper.DEFAULT_ORDER;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           <span class="hljs-comment">// 参数选择器时, 要求spi实现类必须有 @SpiConf 注解, 否则选择器无法获取校验条件参数</span></span><br><span class="line">           <span class="hljs-keyword">if</span> (currentSelector.getSelector() <span class="hljs-keyword">instanceof</span> ParamsSelector) &#123;</span><br><span class="line">               <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"spiImpl must contain annotation @SpiConf!"</span>);</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">           map = Collections.emptyMap();</span><br><span class="line">       &#125; <span class="hljs-keyword">else</span> &#123;</span><br><span class="line">           implName = spiConf.name();</span><br><span class="line">           <span class="hljs-keyword">if</span> (StringUtils.isBlank(implName)) &#123;</span><br><span class="line">               implName = t.getClass().getSimpleName();</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line">           implOrder = spiConf.order() &lt; <span class="hljs-number">0</span> ? SpiImplWrapper.DEFAULT_ORDER : spiConf.order();</span><br><span class="line"></span><br><span class="line">           map = parseParms(spiConf.params());</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       <span class="hljs-comment">// 添加一个类级别的封装类</span></span><br><span class="line">       spiServiceList.add(<span class="hljs-keyword">new</span> SpiImplWrapper&lt;&gt;(t, implOrder, implName, map));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">       <span class="hljs-comment">// todo 改成 getMethods(), 但是过滤掉 Object类中的基础方法</span></span><br><span class="line">       Method[] methods = t.getClass().getDeclaredMethods();</span><br><span class="line">       String methodImplName;</span><br><span class="line">       <span class="hljs-keyword">int</span> methodImplOrder;</span><br><span class="line">       Map&lt;String, String&gt; methodParams;</span><br><span class="line">       <span class="hljs-keyword">for</span> (Method method : methods) &#123;</span><br><span class="line">           spiConf = method.getAnnotation(SpiConf.class);</span><br><span class="line">           <span class="hljs-keyword">if</span> (spiConf == <span class="hljs-keyword">null</span>) &#123;</span><br><span class="line">               <span class="hljs-keyword">continue</span>;</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           <span class="hljs-comment">// 方法上有自定义注解, 且定义的name与类实现名不同, 则直接采用</span></span><br><span class="line">           <span class="hljs-comment">// 否则采用  ServiceName_MethodName 方式定义</span></span><br><span class="line">           <span class="hljs-keyword">if</span> (StringUtils.isBlank(spiConf.name()) || implName.equals(spiConf.name())) &#123;</span><br><span class="line">               methodImplName = implName + <span class="hljs-string">"_"</span> + method.getName();</span><br><span class="line">           &#125; <span class="hljs-keyword">else</span> &#123;</span><br><span class="line">               methodImplName = spiConf.name();</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           <span class="hljs-comment">// 优先级, 以最小的为准 （即一个类上的优先级很低, 也可以定义优先级高的方法）</span></span><br><span class="line">           <span class="hljs-comment">// 方法注解未定义顺序时, 继承类上的顺序</span></span><br><span class="line">           methodImplOrder = Math.min(implOrder, spiConf.order() &lt; <span class="hljs-number">0</span> ? implOrder : spiConf.order());</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           <span class="hljs-comment">// 自适应方法的参数限制, 要求继承类上的参数</span></span><br><span class="line">           methodParams = parseParms(spiConf.params());</span><br><span class="line">           <span class="hljs-keyword">if</span> (map.size() &gt; <span class="hljs-number">0</span>) &#123; <span class="hljs-comment">// 方法的参数限定会继承类上的参数限定</span></span><br><span class="line">               <span class="hljs-keyword">if</span> (methodParams.size() == <span class="hljs-number">0</span>) &#123;</span><br><span class="line">                   methodParams = map;</span><br><span class="line">               &#125; <span class="hljs-keyword">else</span> &#123;</span><br><span class="line">                   methodParams.putAll(map);</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">           spiServiceMethodList.add(<span class="hljs-keyword">new</span> SpiImplWrapper&lt;&gt;(t, methodImplOrder, methodImplName, methodParams));</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">if</span> (spiServiceList.size() == <span class="hljs-number">0</span>) &#123;</span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"no spiImpl implements spi: "</span> + spiInterfaceType);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">this</span>.spiImplClassCacheMap = initSpiImplMap(spiServiceList);</span><br><span class="line">   <span class="hljs-keyword">this</span>.spiImplMethodCacheMap = initSpiImplMap(spiServiceMethodList);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">private</span> Map&lt;String, SpiImplWrapper&lt;T&gt;&gt; initSpiImplMap(List&lt;SpiImplWrapper&lt;T&gt;&gt; list) &#123;</span><br><span class="line">   <span class="hljs-comment">// 映射为map, 限定不能重名</span></span><br><span class="line">   Map&lt;String, SpiImplWrapper&lt;T&gt;&gt; tempMap = <span class="hljs-keyword">new</span> ConcurrentHashMap&lt;&gt;();</span><br><span class="line">   <span class="hljs-keyword">for</span> (SpiImplWrapper&lt;T&gt; wrapper : list) &#123;</span><br><span class="line">       <span class="hljs-keyword">if</span> (tempMap.containsKey(wrapper.getName())) &#123;</span><br><span class="line">           <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"duplicate spiImpl name "</span> + wrapper.getName());</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       tempMap.put(wrapper.getName(), wrapper);</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="hljs-keyword">return</span> tempMap;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面的逻辑可以分为两块，一块是上半边的初始化，获取<code>spiImplClassCacheMap</code>;<br>下一块则是扫描实现类的所有方法，将方法上标有<code>@SpiConf</code>注解的捞出来，用于初始化 <code>spiImplMethodCacheMap</code></p>
<h4 id="说明-4"><a href="#说明-4" class="headerlink" title="说明"></a>说明</h4><ol>
<li><p>缓存结构中value为  <code>SpiImplWrapper</code></p>
<ul>
<li><p>缓存value并不是简单的实现类，封装类的定义如下，将条件和排序也同时封装进去了</p>
  <figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">private</span> T spiImpl;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> order;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">* spiImpl 的标识name, 要求唯一</span></span><br><span class="line"><span class="hljs-comment">* &lt;p/&gt;</span></span><br><span class="line"><span class="hljs-comment">* &#123;<span class="hljs-doctag">@link</span> com.hust.hui.quicksilver.spi.selector.DefaultSelector 选择具体的SpiImpl 时使用&#125;</span></span><br><span class="line"><span class="hljs-comment">*/</span></span><br><span class="line"><span class="hljs-keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment">* 参数校验规则</span></span><br><span class="line"><span class="hljs-comment">* &lt;p/&gt;</span></span><br><span class="line"><span class="hljs-comment">* &#123;<span class="hljs-doctag">@link</span> com.hust.hui.quicksilver.spi.selector.ParamsSelector&#125; 选择具体的SpiImpl 时使用</span></span><br><span class="line"><span class="hljs-comment">* 要求每个实现类都有注解  &#123;<span class="hljs-doctag">@link</span> SpiConf&#125;</span></span><br><span class="line"><span class="hljs-comment">*/</span></span><br><span class="line"><span class="hljs-keyword">private</span> Map&lt;String, String&gt; paramCondition;</span><br></pre></td></tr></table></figure>
</li>
<li><p>name 的定义，类与方法两个纬度的缓存中，定义规则不同，具体可以看《缓存结构》这里的说明</p>
</li>
</ul>
</li>
<li><p>采用 <code>ParamsSelector</code> 时， 要求  <code>@SpiConf</code> 注解必须存在</p>
</li>
<li><p>注意扫描所有方法对应的注解, spi实现类，如果存在继承则会出现问题</p>
<pre><code>// todo 改成 getMethods(), 但是过滤掉 Object类中的基础方法
Method[] methods = t.getClass().getDeclaredMethods();
</code></pre></li>
</ol>
<h2 id="动态代码生成"><a href="#动态代码生成" class="headerlink" title="动态代码生成"></a>动态代码生成</h2><blockquote>
<p>上面在谈论动态使用的时候，采用的方案是，生成一个代理类，实现spi接口， 在具体的实现逻辑中，使用选择器来获取满足条件的实现类，然后执行相应的方法</p>
</blockquote>
<h3 id="1-代理类格式"><a href="#1-代理类格式" class="headerlink" title="1. 代理类格式"></a>1. 代理类格式</h3><p>采用倒推方式，先给出一个实际的代理类如下，具体的实现中其实只有两行代码</p>
<ol>
<li>获取具体的实现类 （调用上面的 <code>SpiLoader.getService(conf, methodName</code>）</li>
<li>执行实现类的接口</li>
</ol>
<figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-keyword">package</span> com.hust.hui.quicksilver.spi.test.print;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">import</span> com.hust.hui.quicksilver.spi.SpiLoader;</span><br><span class="line"></span><br><span class="line"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">IPrint</span>$<span class="hljs-title">Proxy</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">com</span>.<span class="hljs-title">hust</span>.<span class="hljs-title">hui</span>.<span class="hljs-title">quicksilver</span>.<span class="hljs-title">spi</span>.<span class="hljs-title">test</span>.<span class="hljs-title">print</span>.<span class="hljs-title">IPrint</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">print</span><span class="hljs-params">(java.lang.String arg0)</span> </span>&#123;</span><br><span class="line">        <span class="hljs-keyword">try</span> &#123;</span><br><span class="line">            com.hust.hui.quicksilver.spi.test.print.IPrint spiImpl = SpiLoader.load(com.hust.hui.quicksilver.spi.test.print.IPrint.class).getService(arg0, <span class="hljs-string">"print"</span>);</span><br><span class="line">            spiImpl.print(arg0);</span><br><span class="line">        &#125; <span class="hljs-keyword">catch</span> (com.hust.hui.quicksilver.spi.exception.NoSpiMatchException e) &#123;</span><br><span class="line">            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> java.lang.RuntimeException(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">adaptivePrint</span><span class="hljs-params">(java.lang.String arg0, java.lang.String arg1)</span> </span>&#123;</span><br><span class="line">        <span class="hljs-keyword">try</span> &#123;</span><br><span class="line">            com.hust.hui.quicksilver.spi.test.print.IPrint spiImpl = SpiLoader.load(com.hust.hui.quicksilver.spi.test.print.IPrint.class).getService(arg0, <span class="hljs-string">"adaptivePrint"</span>);</span><br><span class="line">            spiImpl.adaptivePrint(arg0, arg1);</span><br><span class="line">        &#125; <span class="hljs-keyword">catch</span> (com.hust.hui.quicksilver.spi.exception.NoSpiMatchException e) &#123;</span><br><span class="line">            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> java.lang.RuntimeException(e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>上面给出了一个代理类的演示，那么剩下两个问题，一个是如何生成代理类； 一个是如何运行代理类（上面是java代码，我们知道运行得是字节码才行）</p>
<h4 id="代理类生成"><a href="#代理类生成" class="headerlink" title="代理类生成"></a>代理类生成</h4><p>对着上面的实现，反推代码生成，其实比较简单了，无非就是生成一大串的String罢了，这里真没什么特殊的，贴下实现，逻辑省略</p>
<figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-comment">/**</span></span><br><span class="line"><span class="hljs-comment"> * 构建SPI接口的实现代理类, 在执行动态适配的方法时, 调用SpiLoader的 spiImpl选择器, 选择具体的实现类执行</span></span><br><span class="line"><span class="hljs-comment"> *</span></span><br><span class="line"><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span></span><br><span class="line"><span class="hljs-comment"> */</span></span><br><span class="line"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">buildTempImpl</span><span class="hljs-params">(Class type)</span> </span>&#123;</span><br><span class="line">    StringBuilder codeBuilder = <span class="hljs-keyword">new</span> StringBuilder();</span><br><span class="line"></span><br><span class="line">    codeBuilder.append(<span class="hljs-string">"package "</span>).append(type.getPackage().getName()).append(<span class="hljs-string">";"</span>);</span><br><span class="line">    codeBuilder.append(<span class="hljs-string">"\nimport "</span>).append(SpiLoader.class.getName()).append(<span class="hljs-string">";"</span>);</span><br><span class="line">    codeBuilder.append(<span class="hljs-string">"\npublic class "</span>).append(type.getSimpleName()).append(<span class="hljs-string">"$Proxy implements "</span>).append(type.getCanonicalName()).append(<span class="hljs-string">" &#123;\n"</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    Method[] methods = type.getMethods();</span><br><span class="line">    <span class="hljs-keyword">for</span> (Method method : methods) &#123;</span><br><span class="line">        Class&lt;?&gt; returnType = method.getReturnType(); <span class="hljs-comment">//函数返回值</span></span><br><span class="line">        Class&lt;?&gt;[] parameterTypes = method.getParameterTypes();<span class="hljs-comment">//函数参数列表</span></span><br><span class="line">        Class&lt;?&gt;[] exceptionTypes = method.getExceptionTypes();<span class="hljs-comment">//函数异常列表</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="hljs-comment">// build method code</span></span><br><span class="line">        StringBuilder code = <span class="hljs-keyword">new</span> StringBuilder(<span class="hljs-number">512</span>);</span><br><span class="line">        <span class="hljs-keyword">if</span> (parameterTypes.length &lt; <span class="hljs-number">0</span>) &#123;   <span class="hljs-comment">//检查该函数参数列表中，第一个参数作为选择器参数</span></span><br><span class="line">            code.append(<span class="hljs-string">"throw new IllegalArgumentException(\"there should be one argument for selector to choose spiImpl\")"</span>);</span><br><span class="line">        &#125; <span class="hljs-keyword">else</span> &#123; <span class="hljs-comment">// 没有 SpiAdaptive注解的, 采用默认的注解方式</span></span><br><span class="line">            code.append(<span class="hljs-string">"try&#123;\n"</span>);</span><br><span class="line">            code.append(type.getName()).append(<span class="hljs-string">" spiImpl="</span>)</span><br><span class="line">                    .append(<span class="hljs-string">"SpiLoader.load("</span>)</span><br><span class="line">                    .append(type.getName()).append(<span class="hljs-string">".class"</span>)</span><br><span class="line">                    .append(<span class="hljs-string">").getService(arg0,\""</span>)</span><br><span class="line">                    .append(method.getName())</span><br><span class="line">                    .append(<span class="hljs-string">"\");"</span>);</span><br><span class="line"></span><br><span class="line">            <span class="hljs-keyword">if</span> (!<span class="hljs-string">"void"</span>.equals(returnType.getName())) &#123;</span><br><span class="line">                code.append(<span class="hljs-string">"return "</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            code.append(<span class="hljs-string">"spiImpl."</span>).append(method.getName()).append(<span class="hljs-string">"(arg0"</span>);</span><br><span class="line">            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i &lt; parameterTypes.length; i++) &#123;</span><br><span class="line">                code.append(<span class="hljs-string">","</span>).append(<span class="hljs-string">"arg"</span>).append(i);</span><br><span class="line">            &#125;</span><br><span class="line">            code.append(<span class="hljs-string">");"</span>);</span><br><span class="line">            code.append(<span class="hljs-string">"\n&#125; catch(com.hust.hui.quicksilver.spi.exception.NoSpiMatchException e)&#123;\nthrow new java.lang.RuntimeException(e);\n&#125;"</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="hljs-comment">// build method signature</span></span><br><span class="line">        codeBuilder.append(<span class="hljs-string">"\npublic "</span>).append(returnType.getName()).append(<span class="hljs-string">" "</span>).append(method.getName())</span><br><span class="line">                .append(<span class="hljs-string">"("</span>).append(parameterTypes[<span class="hljs-number">0</span>].getName()).append(<span class="hljs-string">" arg0"</span>);</span><br><span class="line"></span><br><span class="line">        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i &lt; parameterTypes.length; i++) &#123;</span><br><span class="line">            codeBuilder.append(<span class="hljs-string">", "</span>).append(parameterTypes[i].getName()).append(<span class="hljs-string">" arg"</span>).append(i);</span><br><span class="line">        &#125;</span><br><span class="line">        codeBuilder.append(<span class="hljs-string">") "</span>);</span><br><span class="line">        <span class="hljs-keyword">if</span> (exceptionTypes.length &gt; <span class="hljs-number">0</span>) &#123;</span><br><span class="line">            codeBuilder.append(<span class="hljs-string">"throw "</span>).append(exceptionTypes[<span class="hljs-number">0</span>].getName());</span><br><span class="line">            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i &lt; exceptionTypes.length; i++) &#123;</span><br><span class="line">                codeBuilder.append(<span class="hljs-string">", "</span>).append(exceptionTypes[i].getName());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        codeBuilder.append(<span class="hljs-string">"&#123;\n"</span>);</span><br><span class="line">        codeBuilder.append(code.toString()).append(<span class="hljs-string">"\n&#125;"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    codeBuilder.append(<span class="hljs-string">"\n&#125;"</span>);</span><br><span class="line">    <span class="hljs-keyword">return</span> codeBuilder.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="动态编译运行"><a href="#动态编译运行" class="headerlink" title="动态编译运行"></a>动态编译运行</h4><p>动态编译，最开始想的是利用jdk的动态编译方式，试来试去没搞成功，然后选择了一个折中的方案，把代理类看成是groovy代码，利用 GroovyEngine 来实现动态运行, 这一块的逻辑也超级简单，下面的短短几行代码即可； 后面有空单独研究下java的动态编译</p>
<figure class="highlight java hljs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">"unchecked"</span>)</span><br><span class="line"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> &lt;T&gt; <span class="hljs-function">T <span class="hljs-title">compile</span><span class="hljs-params">(String code, Class&lt;T&gt; interfaceType, ClassLoader classLoader)</span> <span class="hljs-keyword">throws</span> SpiProxyCompileException </span>&#123;</span><br><span class="line">   GroovyClassLoader loader = <span class="hljs-keyword">new</span> GroovyClassLoader(classLoader);</span><br><span class="line">   Class clz = loader.parseClass(code);</span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">if</span> (!interfaceType.isAssignableFrom(clz)) &#123;</span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"illegal proxy type!"</span>);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   <span class="hljs-keyword">try</span> &#123;</span><br><span class="line">       <span class="hljs-keyword">return</span> (T) clz.newInstance();</span><br><span class="line">   &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;</span><br><span class="line">       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> SpiProxyCompileException(<span class="hljs-string">"init spiProxy error! msg: "</span> + e.getMessage());</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>至此，核心的东西基本上都过了一遍，主要的设计思路，实现逻辑，执行流程都说完了</p>
<h3 id="博客系列链接："><a href="#博客系列链接：" class="headerlink" title="博客系列链接："></a>博客系列链接：</h3><ul>
<li><a href="/hexblog/2018/05/30/SPI%E6%A1%86%E6%9E%B6%E5%AE%9E%E7%8E%B0%E4%B9%8B%E6%97%85%E5%9B%9B%EF%BC%9A%E4%BD%BF%E7%94%A8%E6%B5%8B%E8%AF%95/">SPI框架实现之旅四：使用测试</a></li>
<li><a href="/hexblog/2018/05/30/SPI%E6%A1%86%E6%9E%B6%E5%AE%9E%E7%8E%B0%E4%B9%8B%E6%97%85%E4%B8%89%EF%BC%9A%E5%AE%9E%E7%8E%B0%E8%AF%B4%E6%98%8E/">SPI框架实现之旅三：实现说明</a></li>
<li><a href="/hexblog/2018/05/30/SPI%E6%A1%86%E6%9E%B6%E5%AE%9E%E7%8E%B0%E4%B9%8B%E6%97%85%E4%BA%8C%EF%BC%9A%E6%95%B4%E4%BD%93%E8%AE%BE%E8%AE%A1/">SPI框架实现之旅二：整体设计</a></li>
<li><a href="/hexblog/2017/05/29/SPI%E6%A1%86%E6%9E%B6%E5%AE%9E%E7%8E%B0%E4%B9%8B%E6%97%85%E4%B8%80%EF%BC%9A%E8%83%8C%E6%99%AF%E4%BB%8B%E7%BB%8D/">SPI框架实现之旅一：背景介绍</a></li>
</ul>
<h3 id="项目-QuickAlarm"><a href="#项目-QuickAlarm" class="headerlink" title="项目: QuickAlarm"></a>项目: QuickAlarm</h3><ul>
<li>项目地址： <a href="https://github.com/liuyueyi/quick-spi" target="_blank" rel="noopener">Quick-SPI</a></li>
<li>博客地址： <a href="https://liuyueyi.github.io/hexblog/" target="_blank" rel="noopener">小灰灰Blog</a></li>
</ul>
<h3 id="个人博客：-Z-blog"><a href="#个人博客：-Z-blog" class="headerlink" title="个人博客： Z+|blog"></a>个人博客： <a href="https://liuyueyi.github.io/hexblog" target="_blank" rel="noopener">Z+|blog</a></h3><p>基于hexo + github pages搭建的个人博客，记录所有学习和工作中的博文，欢迎大家前去逛逛</p>
<h3 id="声明"><a href="#声明" class="headerlink" title="声明"></a>声明</h3><p>尽信书则不如，已上内容，纯属一家之言，因本人能力一般，见识有限，如发现bug或者有更好的建议，随时欢迎批评指正，我的微博地址: <a href="https://weibo.com/p/1005052169825577/home" target="_blank" rel="noopener">小灰灰Blog</a></p>
<h3 id="扫描关注"><a href="#扫描关注" class="headerlink" title="扫描关注"></a>扫描关注</h3><p><img src="https://s17.mogucdn.com/mlcdn/c45406/180209_74fic633aebgh5dgfhid2fiiggc99_1220x480.png" alt="QrCode"></p>


            
        </div>
        
        <div class="level is-size-7 is-uppercase">
            <div class="level-start">
                <div class="level-item">
                    <span class="is-size-6 has-text-grey has-mr-7">#</span>
                    <a class="has-link-grey -link" href="/hexblog/tags/Java/">Java</a>, <a class="has-link-grey -link" href="/hexblog/tags/技术方案/">技术方案</a>
                </div>
            </div>
        </div>
        
        
        
        <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more"></a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博"></a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网"></a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a>
</div>
<script>window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "2", "bdPic": "", "bdStyle": "0", "bdSize": "16" }, "share": {} }; with (document) 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];</script>
        
    </div>
</div>



<div class="card">
    <div class="card-content">
        <h3 class="menu-label has-text-centered">喜欢这篇文章？打赏一下作者吧</h3>
        <div class="buttons is-centered">
            
                
<a class="button is-info donate">
    <span class="icon is-small">
        <i class="fab fa-alipay"></i>
    </span>
    <span>支付宝</span>
    <div class="qrcode"><img src="https://s3.mogucdn.com/mlcdn/c45406/180104_0e6afl33b23lacj6ji2d7d060aiak_798x800.png" alt="支付宝"></div>
</a>

                
                
<a class="button is-success donate">
    <span class="icon is-small">
        <i class="fab fa-weixin"></i>
    </span>
    <span>微信</span>
    <div class="qrcode"><img src="https://s11.mogucdn.com/mlcdn/c45406/180527_09cafb94a5g3lbd5ik6ke0hf649ff_800x798.jpg" alt="微信"></div>
</a>

                
        </div>
    </div>
</div>



<div class="card card-transparent">
    <div class="level post-navigation is-flex-wrap is-mobile">
        
        <div class="level-start">
            <a class="level level-item has-link-grey  article-nav-prev" href="/hexblog/2017/05/30/SPI框架实现之旅四：使用测试/">
                <i class="level-item fas fa-chevron-left"></i>
                <span class="level-item">4. SPI框架实现之旅四：使用测试</span>
            </a>
        </div>
        
        
        <div class="level-end">
            <a class="level level-item has-link-grey  article-nav-next" href="/hexblog/2017/05/28/SPI框架实现之旅二：整体设计/">
                <span class="level-item">2. SPI框架实现之旅二：整体设计</span>
                <i class="level-item fas fa-chevron-right"></i>
            </a>
        </div>
        
    </div>
</div>



<div class="card">
    <div class="card-content">
        <h3 class="title is-5 has-text-weight-normal">评论</h3>
        
<div id="comment-container"></div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@1.4.1/dist/gitalk.css">
<script src="https://cdn.jsdelivr.net/npm/gitalk@1.4.1/dist/gitalk.min.js"></script>
<script>
    var gitalk = new Gitalk({
        clientID: 'f4c5b85c7c1ceb8fbe2d',
        clientSecret: 'e8c365a05e6ab22272bee0b79ab27f69ff10a43a',
        id: 'd2213d45589dac9a66bf31bd00a7369a',
        repo: 'hexblog',
        owner: 'liuyueyi',
        admin: "liuyueyi"
    })
    gitalk.render('comment-container')
</script>

    </div>
</div>
</div>
                




<div class="column is-4-tablet is-4-desktop is-3-widescreen  has-order-1 column-left ">
    
        
<div class="card widget">
    <div class="card-content card-info">
        <nav class="level">
            <div class="level-item has-text-centered">
                <div>
                    
                        <img class="image is-128x128 has-mb-6" src="/hexblog/images/avatar.jpg" alt="一灰灰Blog">
                    
                    
                    <p class="is-size-4 is-block">
                        一灰灰Blog
                    </p>
                    
                    
                    <p class="is-size-6 is-block">
                        Java，服务器后端开发
                    </p>
                    
                    
                    <p class="is-size-6 is-flex is-flex-center has-text-grey">
                        <i class="fas fa-map-marker-alt has-mr-7"></i>
                        <span>Wuhan, China</span>
                    </p>
                    
                </div>
            </div>
        </nav>
        <nav class="level is-mobile">
            <div class="level-item has-text-centered is-marginless">
                <div>
                    
                    <p class="heading">
                        文章
                    </p>
                    <a href="/hexblog/archives">
                    <p class="title has-text-weight-normal">
                        269
                    </p>
                    </a>
                </div>
            </div>
            <div class="level-item has-text-centered is-marginless">
                <div>
                    
                    <p class="heading">
                        分类
                    </p>
                    <a href="/hexblog/categories">
                        <p class="title has-text-weight-normal">
                            70
                        </p>
                    </a>
                </div>
            </div>
            <div class="level-item has-text-centered is-marginless">
                <div>
                
                    <p class="heading">
                        标签
                    </p>
                    <a href="/hexblog/tags">
                    <p class="title has-text-weight-normal">
                        74
                    </p>
                    </a>
                </div>
            </div>
        </nav>
        <div class="level">
            <a class="level-item button is-link is-rounded" href="https://github.com/liuyueyi" target="_blank">
                关注我</a>
        </div>
        
        
        <div class="level is-mobile">
            
            <a class="level-item button is-white is-marginless" target="_blank"
                title="Github" href="https://github.com/liuyueyi">
                
                <i class="fab fa-github"></i>
                
            </a>
            
            <a class="level-item button is-white is-marginless" target="_blank"
                title="Gitee" href="https://gitee.com/liuyueyi">
                
                <i class="fab fa-gg"></i>
                
            </a>
            
            <a class="level-item button is-white is-marginless" target="_blank"
                title="Weibo" href="https://weibo.com/p/1005052169825577/home">
                
                <i class="fab fa-weibo"></i>
                
            </a>
            
            <a class="level-item button is-white is-marginless" target="_blank"
                title="weixin" href="https://s10.mogucdn.com/mlcdn/c45406/171229_1cgld3igbelkbc70cd8af1j3809kb_150x150.jpg">
                
                <i class="fab fa-weixin"></i>
                
            </a>
            
            <a class="level-item button is-white is-marginless" target="_blank"
                title="RSS" href="/hexblog/atom.xml">
                
                <i class="fas fa-rss"></i>
                
            </a>
            
        </div>
        
    </div>
</div>
    
        
    
        

<div class="card widget">
    <div class="card-content">
        <div class="menu">
        <h3 class="menu-label">
            链接
        </h3>
        <ul class="menu-list">
        
            <li>
                <a class="level is-mobile" href="http://spring.hhui.top" target="_blank">
                    <span class="level-left">
                        <span class="level-item">SpringBlog</span>
                    </span>
                    <span class="level-right">
                        <span class="level-item tag">spring.hhui.top</span>
                    </span>
                </a>
            </li>
        
            <li>
                <a class="level is-mobile" href="https://github.com/liuyueyi" target="_blank">
                    <span class="level-left">
                        <span class="level-item">GitHub</span>
                    </span>
                    <span class="level-right">
                        <span class="level-item tag">github.com</span>
                    </span>
                </a>
            </li>
        
            <li>
                <a class="level is-mobile" href="https://zweb.hhui.top" target="_blank">
                    <span class="level-left">
                        <span class="level-item">多媒体工具小站</span>
                    </span>
                    <span class="level-right">
                        <span class="level-item tag">zweb.hhui.top</span>
                    </span>
                </a>
            </li>
        
            <li>
                <a class="level is-mobile" href="https://mweb.hhui.top" target="_blank">
                    <span class="level-left">
                        <span class="level-item">每日十首古诗词</span>
                    </span>
                    <span class="level-right">
                        <span class="level-item tag">mweb.hhui.top</span>
                    </span>
                </a>
            </li>
        
        </ul>
        </div>
    </div>
</div>


    
        
<div class="card widget">
    <div class="card-content">
        <h3 class="menu-label">
            最新文章
        </h3>
        
        <article class="media">
            
            <div class="media-content">
                <div class="content">
                    <div><time class="has-text-grey is-size-7 is-uppercase" datetime="2020-03-28T11:27:12.000Z">2020-03-28</time></div>
                    <a href="/hexblog/2020/03/28/200328-MongoDb系列教程九-文档-Document-查询基础篇/" class="has-link-black-ter is-size-6">200328-MongoDb系列教程九：文档 Document 查询基础篇</a>
                    <p class="is-size-7 is-uppercase">
                        <a class="has-link-grey -link" href="/hexblog/categories/DB/">DB</a> / <a class="has-link-grey -link" href="/hexblog/categories/DB/Mongo/">Mongo</a>
                    </p>
                </div>
            </div>
        </article>
        
        <article class="media">
            
            <div class="media-content">
                <div class="content">
                    <div><time class="has-text-grey is-size-7 is-uppercase" datetime="2020-03-27T03:04:36.000Z">2020-03-27</time></div>
                    <a href="/hexblog/2020/03/27/200327-MongoDb系列教程八-文档-Document-更新姿势/" class="has-link-black-ter is-size-6">200327-MongoDb系列教程八：文档 Document 更新姿势</a>
                    <p class="is-size-7 is-uppercase">
                        <a class="has-link-grey -link" href="/hexblog/categories/DB/">DB</a> / <a class="has-link-grey -link" href="/hexblog/categories/DB/Mongo/">Mongo</a>
                    </p>
                </div>
            </div>
        </article>
        
        <article class="media">
            
            <div class="media-content">
                <div class="content">
                    <div><time class="has-text-grey is-size-7 is-uppercase" datetime="2020-03-26T10:02:03.000Z">2020-03-26</time></div>
                    <a href="/hexblog/2020/03/26/200326-MongoDb系列教程七-文档-Document-删除姿势/" class="has-link-black-ter is-size-6">200326-MongoDb系列教程七：文档 Document 删除姿势</a>
                    <p class="is-size-7 is-uppercase">
                        <a class="has-link-grey -link" href="/hexblog/categories/DB/">DB</a> / <a class="has-link-grey -link" href="/hexblog/categories/DB/Mongo/">Mongo</a>
                    </p>
                </div>
            </div>
        </article>
        
        <article class="media">
            
            <div class="media-content">
                <div class="content">
                    <div><time class="has-text-grey is-size-7 is-uppercase" datetime="2020-03-26T09:04:06.000Z">2020-03-26</time></div>
                    <a href="/hexblog/2020/03/26/200326-MongoDb系列教程六-文档-Document-插入姿势/" class="has-link-black-ter is-size-6">200326-MongoDb系列教程六：文档 Document 插入姿势</a>
                    <p class="is-size-7 is-uppercase">
                        <a class="has-link-grey -link" href="/hexblog/categories/DB/">DB</a> / <a class="has-link-grey -link" href="/hexblog/categories/DB/Mongo/">Mongo</a>
                    </p>
                </div>
            </div>
        </article>
        
        <article class="media">
            
            <div class="media-content">
                <div class="content">
                    <div><time class="has-text-grey is-size-7 is-uppercase" datetime="2020-03-26T08:52:20.000Z">2020-03-26</time></div>
                    <a href="/hexblog/2020/03/26/200326-MongoDb系列教程五-集合-Collection/" class="has-link-black-ter is-size-6">200326-MongoDb系列教程五：集合 Collection</a>
                    <p class="is-size-7 is-uppercase">
                        <a class="has-link-grey -link" href="/hexblog/categories/DB/">DB</a> / <a class="has-link-grey -link" href="/hexblog/categories/DB/Mongo/">Mongo</a>
                    </p>
                </div>
            </div>
        </article>
        
    </div>
</div>

    
        
<div class="card widget">
    <div class="card-content">
        <h3 class="menu-label">
            标签云
        </h3>
        <a href="/hexblog/tags/Android/" style="font-size: 10px;">Android</a> <a href="/hexblog/tags/AutoCloseable/" style="font-size: 10px;">AutoCloseable</a> <a href="/hexblog/tags/BloomFilter/" style="font-size: 10px;">BloomFilter</a> <a href="/hexblog/tags/BugFix/" style="font-size: 10.63px;">BugFix</a> <a href="/hexblog/tags/Bugfix/" style="font-size: 10.63px;">Bugfix</a> <a href="/hexblog/tags/Docker/" style="font-size: 11.88px;">Docker</a> <a href="/hexblog/tags/FastJson/" style="font-size: 10px;">FastJson</a> <a href="/hexblog/tags/Git/" style="font-size: 11.25px;">Git</a> <a href="/hexblog/tags/Groovy/" style="font-size: 10px;">Groovy</a> <a href="/hexblog/tags/Guava/" style="font-size: 11.25px;">Guava</a> <a href="/hexblog/tags/HashMap/" style="font-size: 10px;">HashMap</a> <a href="/hexblog/tags/IO/" style="font-size: 10.63px;">IO</a> <a href="/hexblog/tags/ImageMagic/" style="font-size: 10.63px;">ImageMagic</a> <a href="/hexblog/tags/InfluxDB/" style="font-size: 16.88px;">InfluxDB</a> <a href="/hexblog/tags/InputStream/" style="font-size: 10px;">InputStream</a> <a href="/hexblog/tags/JDK/" style="font-size: 15px;">JDK</a> <a href="/hexblog/tags/JVM/" style="font-size: 11.25px;">JVM</a> <a href="/hexblog/tags/Java/" style="font-size: 20px;">Java</a> <a href="/hexblog/tags/JavaAgent/" style="font-size: 10.63px;">JavaAgent</a> <a href="/hexblog/tags/JavaWeb/" style="font-size: 10.63px;">JavaWeb</a> <a href="/hexblog/tags/Jquery/" style="font-size: 10px;">Jquery</a> <a href="/hexblog/tags/Linux/" style="font-size: 15px;">Linux</a> <a href="/hexblog/tags/List/" style="font-size: 10px;">List</a> <a href="/hexblog/tags/MD5/" style="font-size: 10px;">MD5</a> <a href="/hexblog/tags/Map/" style="font-size: 10px;">Map</a> <a href="/hexblog/tags/Maven/" style="font-size: 10px;">Maven</a> <a href="/hexblog/tags/Mongo/" style="font-size: 10.63px;">Mongo</a> <a href="/hexblog/tags/MongoDB/" style="font-size: 10px;">MongoDB</a> <a href="/hexblog/tags/MongoDb/" style="font-size: 14.38px;">MongoDb</a> <a href="/hexblog/tags/MySql/" style="font-size: 10.63px;">MySql</a> <a href="/hexblog/tags/Mybatis/" style="font-size: 10.63px;">Mybatis</a> <a href="/hexblog/tags/Mysql/" style="font-size: 16.25px;">Mysql</a> <a href="/hexblog/tags/Nginx/" style="font-size: 11.25px;">Nginx</a> <a href="/hexblog/tags/OGNL/" style="font-size: 11.25px;">OGNL</a> <a href="/hexblog/tags/ProtoStuff/" style="font-size: 10.63px;">ProtoStuff</a> <a href="/hexblog/tags/Python/" style="font-size: 19.38px;">Python</a> <a href="/hexblog/tags/QuickAlarm/" style="font-size: 10px;">QuickAlarm</a> <a href="/hexblog/tags/RabbitMQ/" style="font-size: 13.75px;">RabbitMQ</a> <a href="/hexblog/tags/ReactJS/" style="font-size: 10px;">ReactJS</a> <a href="/hexblog/tags/Redis/" style="font-size: 14.38px;">Redis</a> <a href="/hexblog/tags/Shell/" style="font-size: 15.63px;">Shell</a> <a href="/hexblog/tags/Socket/" style="font-size: 10px;">Socket</a> <a href="/hexblog/tags/Solr/" style="font-size: 10px;">Solr</a> <a href="/hexblog/tags/Spring/" style="font-size: 18.75px;">Spring</a> <a href="/hexblog/tags/SpringBoot/" style="font-size: 10px;">SpringBoot</a> <a href="/hexblog/tags/Vue/" style="font-size: 10px;">Vue</a> <a href="/hexblog/tags/WebSocket/" style="font-size: 10px;">WebSocket</a> <a href="/hexblog/tags/Yaml/" style="font-size: 10px;">Yaml</a> <a href="/hexblog/tags/css/" style="font-size: 11.25px;">css</a> <a href="/hexblog/tags/ffmpeg/" style="font-size: 10px;">ffmpeg</a> <a href="/hexblog/tags/gitalk/" style="font-size: 10px;">gitalk</a> <a href="/hexblog/tags/hexo/" style="font-size: 10px;">hexo</a> <a href="/hexblog/tags/jdk/" style="font-size: 10px;">jdk</a> <a href="/hexblog/tags/logger/" style="font-size: 10px;">logger</a> <a href="/hexblog/tags/markdown/" style="font-size: 10px;">markdown</a> <a href="/hexblog/tags/python/" style="font-size: 10px;">python</a> <a href="/hexblog/tags/time/" style="font-size: 10px;">time</a> <a href="/hexblog/tags/乱码/" style="font-size: 10px;">乱码</a> <a href="/hexblog/tags/二维码/" style="font-size: 10px;">二维码</a> <a href="/hexblog/tags/分库分表/" style="font-size: 10px;">分库分表</a> <a href="/hexblog/tags/反射/" style="font-size: 11.25px;">反射</a> <a href="/hexblog/tags/工具/" style="font-size: 12.5px;">工具</a> <a href="/hexblog/tags/并发/" style="font-size: 11.25px;">并发</a> <a href="/hexblog/tags/序列化/" style="font-size: 10px;">序列化</a> <a href="/hexblog/tags/手记/" style="font-size: 13.13px;">手记</a> <a href="/hexblog/tags/技术方案/" style="font-size: 18.13px;">技术方案</a> <a href="/hexblog/tags/指南/" style="font-size: 13.13px;">指南</a> <a href="/hexblog/tags/教程/" style="font-size: 17.5px;">教程</a> <a href="/hexblog/tags/方案设计/" style="font-size: 10px;">方案设计</a> <a href="/hexblog/tags/时区/" style="font-size: 10px;">时区</a> <a href="/hexblog/tags/时间窗口/" style="font-size: 11.25px;">时间窗口</a> <a href="/hexblog/tags/爬虫/" style="font-size: 12.5px;">爬虫</a> <a href="/hexblog/tags/问题记录/" style="font-size: 10px;">问题记录</a> <a href="/hexblog/tags/随笔/" style="font-size: 10px;">随笔</a>
    </div>
</div>

    
        <div class="card widget">
    <div class="card-content">
        <div class="menu">
            <h3 class="menu-label">
                标签
            </h3>
            <div class="field is-grouped is-grouped-multiline">
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Android/">
                        <span class="tag">Android</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/AutoCloseable/">
                        <span class="tag">AutoCloseable</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/BloomFilter/">
                        <span class="tag">BloomFilter</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/BugFix/">
                        <span class="tag">BugFix</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Bugfix/">
                        <span class="tag">Bugfix</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Docker/">
                        <span class="tag">Docker</span>
                        <span class="tag is-grey">4</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/FastJson/">
                        <span class="tag">FastJson</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Git/">
                        <span class="tag">Git</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Groovy/">
                        <span class="tag">Groovy</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Guava/">
                        <span class="tag">Guava</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/HashMap/">
                        <span class="tag">HashMap</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/IO/">
                        <span class="tag">IO</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/ImageMagic/">
                        <span class="tag">ImageMagic</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/InfluxDB/">
                        <span class="tag">InfluxDB</span>
                        <span class="tag is-grey">16</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/InputStream/">
                        <span class="tag">InputStream</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/JDK/">
                        <span class="tag">JDK</span>
                        <span class="tag is-grey">11</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/JVM/">
                        <span class="tag">JVM</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Java/">
                        <span class="tag">Java</span>
                        <span class="tag is-grey">59</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/JavaAgent/">
                        <span class="tag">JavaAgent</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/JavaWeb/">
                        <span class="tag">JavaWeb</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Jquery/">
                        <span class="tag">Jquery</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Linux/">
                        <span class="tag">Linux</span>
                        <span class="tag is-grey">11</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/List/">
                        <span class="tag">List</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/MD5/">
                        <span class="tag">MD5</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Map/">
                        <span class="tag">Map</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Maven/">
                        <span class="tag">Maven</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Mongo/">
                        <span class="tag">Mongo</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/MongoDB/">
                        <span class="tag">MongoDB</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/MongoDb/">
                        <span class="tag">MongoDb</span>
                        <span class="tag is-grey">9</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/MySql/">
                        <span class="tag">MySql</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Mybatis/">
                        <span class="tag">Mybatis</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Mysql/">
                        <span class="tag">Mysql</span>
                        <span class="tag is-grey">15</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Nginx/">
                        <span class="tag">Nginx</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/OGNL/">
                        <span class="tag">OGNL</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/ProtoStuff/">
                        <span class="tag">ProtoStuff</span>
                        <span class="tag is-grey">2</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Python/">
                        <span class="tag">Python</span>
                        <span class="tag is-grey">32</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/QuickAlarm/">
                        <span class="tag">QuickAlarm</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/RabbitMQ/">
                        <span class="tag">RabbitMQ</span>
                        <span class="tag is-grey">8</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/ReactJS/">
                        <span class="tag">ReactJS</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Redis/">
                        <span class="tag">Redis</span>
                        <span class="tag is-grey">9</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Shell/">
                        <span class="tag">Shell</span>
                        <span class="tag is-grey">13</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Socket/">
                        <span class="tag">Socket</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Solr/">
                        <span class="tag">Solr</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Spring/">
                        <span class="tag">Spring</span>
                        <span class="tag is-grey">25</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/SpringBoot/">
                        <span class="tag">SpringBoot</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Vue/">
                        <span class="tag">Vue</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/WebSocket/">
                        <span class="tag">WebSocket</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/Yaml/">
                        <span class="tag">Yaml</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/css/">
                        <span class="tag">css</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/ffmpeg/">
                        <span class="tag">ffmpeg</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/gitalk/">
                        <span class="tag">gitalk</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/hexo/">
                        <span class="tag">hexo</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/jdk/">
                        <span class="tag">jdk</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/logger/">
                        <span class="tag">logger</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/markdown/">
                        <span class="tag">markdown</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/python/">
                        <span class="tag">python</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/time/">
                        <span class="tag">time</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/乱码/">
                        <span class="tag">乱码</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/二维码/">
                        <span class="tag">二维码</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/分库分表/">
                        <span class="tag">分库分表</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/反射/">
                        <span class="tag">反射</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/工具/">
                        <span class="tag">工具</span>
                        <span class="tag is-grey">5</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/并发/">
                        <span class="tag">并发</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/序列化/">
                        <span class="tag">序列化</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/手记/">
                        <span class="tag">手记</span>
                        <span class="tag is-grey">6</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/技术方案/">
                        <span class="tag">技术方案</span>
                        <span class="tag is-grey">22</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/指南/">
                        <span class="tag">指南</span>
                        <span class="tag is-grey">6</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/教程/">
                        <span class="tag">教程</span>
                        <span class="tag is-grey">20</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/方案设计/">
                        <span class="tag">方案设计</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/时区/">
                        <span class="tag">时区</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/时间窗口/">
                        <span class="tag">时间窗口</span>
                        <span class="tag is-grey">3</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/爬虫/">
                        <span class="tag">爬虫</span>
                        <span class="tag is-grey">5</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/问题记录/">
                        <span class="tag">问题记录</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
                <div class="control">
                    <a class="tags has-addons" href="/hexblog/tags/随笔/">
                        <span class="tag">随笔</span>
                        <span class="tag is-grey">1</span>
                    </a>
                </div>
                
            </div>
        </div>
    </div>
</div>
    
    
        <div class="column-right-shadow is-hidden-widescreen ">
        
            
<div class="card widget">
    <div class="card-content">
        <div class="menu">
            <h3 class="menu-label">
                分类
            </h3>
            <ul class="menu-list">
            <li>
        <a class="level is-marginless" href="/hexblog/categories/DB/">
            <span class="level-start">
                <span class="level-item">DB</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">41</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/InfluxDB/">
            <span class="level-start">
                <span class="level-item">InfluxDB</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">16</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/Mongo/">
            <span class="level-start">
                <span class="level-item">Mongo</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">11</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/Mysql/">
            <span class="level-start">
                <span class="level-item">Mysql</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">13</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/分库分表/">
            <span class="level-start">
                <span class="level-item">分库分表</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/">
            <span class="level-start">
                <span class="level-item">Java</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">52</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/Agent/">
            <span class="level-start">
                <span class="level-item">Agent</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/Android/">
            <span class="level-start">
                <span class="level-item">Android</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/Bugfix/">
            <span class="level-start">
                <span class="level-item">Bugfix</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/IO/">
            <span class="level-start">
                <span class="level-item">IO</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/JDK/">
            <span class="level-start">
                <span class="level-item">JDK</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">22</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/JVM/">
            <span class="level-start">
                <span class="level-item">JVM</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">9</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/JavaWeb/">
            <span class="level-start">
                <span class="level-item">JavaWeb</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/其他/">
            <span class="level-start">
                <span class="level-item">其他</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/问题记录/">
            <span class="level-start">
                <span class="level-item">问题记录</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">6</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/">
            <span class="level-start">
                <span class="level-item">Python</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">33</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/Mongo/">
            <span class="level-start">
                <span class="level-item">Mongo</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/MySql/">
            <span class="level-start">
                <span class="level-item">MySql</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/教程/">
            <span class="level-start">
                <span class="level-item">教程</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">25</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/采坑记录/">
            <span class="level-start">
                <span class="level-item">采坑记录</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/项目/">
            <span class="level-start">
                <span class="level-item">项目</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/">
            <span class="level-start">
                <span class="level-item">Quick系列</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">30</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickAlarm/">
            <span class="level-start">
                <span class="level-item">QuickAlarm</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">8</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickCrawler/">
            <span class="level-start">
                <span class="level-item">QuickCrawler</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">5</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickFix/">
            <span class="level-start">
                <span class="level-item">QuickFix</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">6</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickMedia/">
            <span class="level-start">
                <span class="level-item">QuickMedia</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickSpi/">
            <span class="level-start">
                <span class="level-item">QuickSpi</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickTask/">
            <span class="level-start">
                <span class="level-item">QuickTask</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">5</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/">
            <span class="level-start">
                <span class="level-item">Shell</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">39</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/CMD/">
            <span class="level-start">
                <span class="level-item">CMD</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">18</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Docker/">
            <span class="level-start">
                <span class="level-item">Docker</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Git/">
            <span class="level-start">
                <span class="level-item">Git</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Maven/">
            <span class="level-start">
                <span class="level-item">Maven</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Ngins/">
            <span class="level-start">
                <span class="level-item">Ngins</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Nginx/">
            <span class="level-start">
                <span class="level-item">Nginx</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/环境搭建/">
            <span class="level-start">
                <span class="level-item">环境搭建</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">9</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/">
            <span class="level-start">
                <span class="level-item">前端</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">8</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Chrome/">
            <span class="level-start">
                <span class="level-item">Chrome</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Css/">
            <span class="level-start">
                <span class="level-item">Css</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Jquery/">
            <span class="level-start">
                <span class="level-item">Jquery</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/ReactJS/">
            <span class="level-start">
                <span class="level-item">ReactJS</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Vue/">
            <span class="level-start">
                <span class="level-item">Vue</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/工具/">
            <span class="level-start">
                <span class="level-item">工具</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">9</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/工具/工具类/">
            <span class="level-start">
                <span class="level-item">工具类</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">6</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/工具/插件系列/">
            <span class="level-start">
                <span class="level-item">插件系列</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/">
            <span class="level-start">
                <span class="level-item">开源</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">46</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Guava/">
            <span class="level-start">
                <span class="level-item">Guava</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Hexo/">
            <span class="level-start">
                <span class="level-item">Hexo</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Hystrix/">
            <span class="level-start">
                <span class="level-item">Hystrix</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Mybatis/">
            <span class="level-start">
                <span class="level-item">Mybatis</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/OGNL/">
            <span class="level-start">
                <span class="level-item">OGNL</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/RabbitMQ/">
            <span class="level-start">
                <span class="level-item">RabbitMQ</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">8</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Redis/">
            <span class="level-start">
                <span class="level-item">Redis</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Solr/">
            <span class="level-start">
                <span class="level-item">Solr</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Spring/">
            <span class="level-start">
                <span class="level-item">Spring</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">24</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Yaml/">
            <span class="level-start">
                <span class="level-item">Yaml</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/火花/">
            <span class="level-start">
                <span class="level-item">火花</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/随笔/">
            <span class="level-start">
                <span class="level-item">随笔</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">7</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/随笔/idea/">
            <span class="level-start">
                <span class="level-item">idea</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/随笔/吐槽/">
            <span class="level-start">
                <span class="level-item">吐槽</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li>
            </ul>
        </div>
    </div>
</div>
        
            <div class="card widget">
    <div class="card-content">
        <div class="menu">
        <h3 class="menu-label">
            归档
        </h3>
        <ul class="menu-list">
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2020/03/">
                <span class="level-start">
                    <span class="level-item">三月 2020</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">14</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2020/02/">
                <span class="level-start">
                    <span class="level-item">二月 2020</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">1</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2020/01/">
                <span class="level-start">
                    <span class="level-item">一月 2020</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">4</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/12/">
                <span class="level-start">
                    <span class="level-item">十二月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">5</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/11/">
                <span class="level-start">
                    <span class="level-item">十一月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">6</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/10/">
                <span class="level-start">
                    <span class="level-item">十月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">2</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/09/">
                <span class="level-start">
                    <span class="level-item">九月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">4</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/08/">
                <span class="level-start">
                    <span class="level-item">八月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">5</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/07/">
                <span class="level-start">
                    <span class="level-item">七月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/06/">
                <span class="level-start">
                    <span class="level-item">六月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">7</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/05/">
                <span class="level-start">
                    <span class="level-item">五月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">12</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/04/">
                <span class="level-start">
                    <span class="level-item">四月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">7</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/03/">
                <span class="level-start">
                    <span class="level-item">三月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">7</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/02/">
                <span class="level-start">
                    <span class="level-item">二月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">3</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/01/">
                <span class="level-start">
                    <span class="level-item">一月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">14</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/12/">
                <span class="level-start">
                    <span class="level-item">十二月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">8</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/11/">
                <span class="level-start">
                    <span class="level-item">十一月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">10</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/10/">
                <span class="level-start">
                    <span class="level-item">十月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">1</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/09/">
                <span class="level-start">
                    <span class="level-item">九月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">13</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/08/">
                <span class="level-start">
                    <span class="level-item">八月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/07/">
                <span class="level-start">
                    <span class="level-item">七月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">23</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/06/">
                <span class="level-start">
                    <span class="level-item">六月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">22</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/05/">
                <span class="level-start">
                    <span class="level-item">五月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/04/">
                <span class="level-start">
                    <span class="level-item">四月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/03/">
                <span class="level-start">
                    <span class="level-item">三月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">16</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/02/">
                <span class="level-start">
                    <span class="level-item">二月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">10</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/01/">
                <span class="level-start">
                    <span class="level-item">一月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">13</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/12/">
                <span class="level-start">
                    <span class="level-item">十二月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">6</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/09/">
                <span class="level-start">
                    <span class="level-item">九月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">1</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/08/">
                <span class="level-start">
                    <span class="level-item">八月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">3</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/07/">
                <span class="level-start">
                    <span class="level-item">七月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">2</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/06/">
                <span class="level-start">
                    <span class="level-item">六月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">2</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/05/">
                <span class="level-start">
                    <span class="level-item">五月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">4</span>
                </span>
            </a>
        </li>
        
        </ul>
        </div>
    </div>
</div>
        
        </div>
    
</div>

                




<div class="column is-4-tablet is-4-desktop is-2-widescreen is-hidden-touch is-hidden-desktop-only has-order-3 column-right ">
    
        
<div class="card widget">
    <div class="card-content">
        <div class="menu">
            <h3 class="menu-label">
                分类
            </h3>
            <ul class="menu-list">
            <li>
        <a class="level is-marginless" href="/hexblog/categories/DB/">
            <span class="level-start">
                <span class="level-item">DB</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">41</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/InfluxDB/">
            <span class="level-start">
                <span class="level-item">InfluxDB</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">16</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/Mongo/">
            <span class="level-start">
                <span class="level-item">Mongo</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">11</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/Mysql/">
            <span class="level-start">
                <span class="level-item">Mysql</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">13</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/DB/分库分表/">
            <span class="level-start">
                <span class="level-item">分库分表</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/">
            <span class="level-start">
                <span class="level-item">Java</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">52</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/Agent/">
            <span class="level-start">
                <span class="level-item">Agent</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/Android/">
            <span class="level-start">
                <span class="level-item">Android</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/Bugfix/">
            <span class="level-start">
                <span class="level-item">Bugfix</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/IO/">
            <span class="level-start">
                <span class="level-item">IO</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/JDK/">
            <span class="level-start">
                <span class="level-item">JDK</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">22</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/JVM/">
            <span class="level-start">
                <span class="level-item">JVM</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">9</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/JavaWeb/">
            <span class="level-start">
                <span class="level-item">JavaWeb</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/其他/">
            <span class="level-start">
                <span class="level-item">其他</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Java/问题记录/">
            <span class="level-start">
                <span class="level-item">问题记录</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">6</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/">
            <span class="level-start">
                <span class="level-item">Python</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">33</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/Mongo/">
            <span class="level-start">
                <span class="level-item">Mongo</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/MySql/">
            <span class="level-start">
                <span class="level-item">MySql</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/教程/">
            <span class="level-start">
                <span class="level-item">教程</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">25</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/采坑记录/">
            <span class="level-start">
                <span class="level-item">采坑记录</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Python/项目/">
            <span class="level-start">
                <span class="level-item">项目</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/">
            <span class="level-start">
                <span class="level-item">Quick系列</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">30</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickAlarm/">
            <span class="level-start">
                <span class="level-item">QuickAlarm</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">8</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickCrawler/">
            <span class="level-start">
                <span class="level-item">QuickCrawler</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">5</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickFix/">
            <span class="level-start">
                <span class="level-item">QuickFix</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">6</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickMedia/">
            <span class="level-start">
                <span class="level-item">QuickMedia</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickSpi/">
            <span class="level-start">
                <span class="level-item">QuickSpi</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Quick系列/QuickTask/">
            <span class="level-start">
                <span class="level-item">QuickTask</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">5</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/">
            <span class="level-start">
                <span class="level-item">Shell</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">39</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/CMD/">
            <span class="level-start">
                <span class="level-item">CMD</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">18</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Docker/">
            <span class="level-start">
                <span class="level-item">Docker</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Git/">
            <span class="level-start">
                <span class="level-item">Git</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Maven/">
            <span class="level-start">
                <span class="level-item">Maven</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Ngins/">
            <span class="level-start">
                <span class="level-item">Ngins</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/Nginx/">
            <span class="level-start">
                <span class="level-item">Nginx</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/Shell/环境搭建/">
            <span class="level-start">
                <span class="level-item">环境搭建</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">9</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/">
            <span class="level-start">
                <span class="level-item">前端</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">8</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Chrome/">
            <span class="level-start">
                <span class="level-item">Chrome</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Css/">
            <span class="level-start">
                <span class="level-item">Css</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Jquery/">
            <span class="level-start">
                <span class="level-item">Jquery</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/ReactJS/">
            <span class="level-start">
                <span class="level-item">ReactJS</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/前端/Vue/">
            <span class="level-start">
                <span class="level-item">Vue</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/工具/">
            <span class="level-start">
                <span class="level-item">工具</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">9</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/工具/工具类/">
            <span class="level-start">
                <span class="level-item">工具类</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">6</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/工具/插件系列/">
            <span class="level-start">
                <span class="level-item">插件系列</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/">
            <span class="level-start">
                <span class="level-item">开源</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">46</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Guava/">
            <span class="level-start">
                <span class="level-item">Guava</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Hexo/">
            <span class="level-start">
                <span class="level-item">Hexo</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Hystrix/">
            <span class="level-start">
                <span class="level-item">Hystrix</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Mybatis/">
            <span class="level-start">
                <span class="level-item">Mybatis</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">2</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/OGNL/">
            <span class="level-start">
                <span class="level-item">OGNL</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/RabbitMQ/">
            <span class="level-start">
                <span class="level-item">RabbitMQ</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">8</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Redis/">
            <span class="level-start">
                <span class="level-item">Redis</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">3</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Solr/">
            <span class="level-start">
                <span class="level-item">Solr</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Spring/">
            <span class="level-start">
                <span class="level-item">Spring</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">24</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/开源/Yaml/">
            <span class="level-start">
                <span class="level-item">Yaml</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li><li>
        <a class="level is-marginless" href="/hexblog/categories/火花/">
            <span class="level-start">
                <span class="level-item">火花</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">4</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/随笔/">
            <span class="level-start">
                <span class="level-item">随笔</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">7</span>
            </span>
        </a><ul><li>
        <a class="level is-marginless" href="/hexblog/categories/随笔/idea/">
            <span class="level-start">
                <span class="level-item">idea</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li><li>
        <a class="level is-marginless" href="/hexblog/categories/随笔/吐槽/">
            <span class="level-start">
                <span class="level-item">吐槽</span>
            </span>
            <span class="level-end">
                <span class="level-item tag">1</span>
            </span>
        </a></li></ul></li>
            </ul>
        </div>
    </div>
</div>
    
        <div class="card widget">
    <div class="card-content">
        <div class="menu">
        <h3 class="menu-label">
            归档
        </h3>
        <ul class="menu-list">
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2020/03/">
                <span class="level-start">
                    <span class="level-item">三月 2020</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">14</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2020/02/">
                <span class="level-start">
                    <span class="level-item">二月 2020</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">1</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2020/01/">
                <span class="level-start">
                    <span class="level-item">一月 2020</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">4</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/12/">
                <span class="level-start">
                    <span class="level-item">十二月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">5</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/11/">
                <span class="level-start">
                    <span class="level-item">十一月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">6</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/10/">
                <span class="level-start">
                    <span class="level-item">十月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">2</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/09/">
                <span class="level-start">
                    <span class="level-item">九月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">4</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/08/">
                <span class="level-start">
                    <span class="level-item">八月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">5</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/07/">
                <span class="level-start">
                    <span class="level-item">七月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/06/">
                <span class="level-start">
                    <span class="level-item">六月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">7</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/05/">
                <span class="level-start">
                    <span class="level-item">五月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">12</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/04/">
                <span class="level-start">
                    <span class="level-item">四月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">7</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/03/">
                <span class="level-start">
                    <span class="level-item">三月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">7</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/02/">
                <span class="level-start">
                    <span class="level-item">二月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">3</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2019/01/">
                <span class="level-start">
                    <span class="level-item">一月 2019</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">14</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/12/">
                <span class="level-start">
                    <span class="level-item">十二月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">8</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/11/">
                <span class="level-start">
                    <span class="level-item">十一月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">10</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/10/">
                <span class="level-start">
                    <span class="level-item">十月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">1</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/09/">
                <span class="level-start">
                    <span class="level-item">九月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">13</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/08/">
                <span class="level-start">
                    <span class="level-item">八月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/07/">
                <span class="level-start">
                    <span class="level-item">七月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">23</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/06/">
                <span class="level-start">
                    <span class="level-item">六月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">22</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/05/">
                <span class="level-start">
                    <span class="level-item">五月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/04/">
                <span class="level-start">
                    <span class="level-item">四月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">11</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/03/">
                <span class="level-start">
                    <span class="level-item">三月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">16</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/02/">
                <span class="level-start">
                    <span class="level-item">二月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">10</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2018/01/">
                <span class="level-start">
                    <span class="level-item">一月 2018</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">13</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/12/">
                <span class="level-start">
                    <span class="level-item">十二月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">6</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/09/">
                <span class="level-start">
                    <span class="level-item">九月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">1</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/08/">
                <span class="level-start">
                    <span class="level-item">八月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">3</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/07/">
                <span class="level-start">
                    <span class="level-item">七月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">2</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/06/">
                <span class="level-start">
                    <span class="level-item">六月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">2</span>
                </span>
            </a>
        </li>
        
        <li>
            <a class="level is-marginless" href="/hexblog/archives/2017/05/">
                <span class="level-start">
                    <span class="level-item">五月 2017</span>
                </span>
                <span class="level-end">
                    <span class="level-item tag">4</span>
                </span>
            </a>
        </li>
        
        </ul>
        </div>
    </div>
</div>
    
    
</div>

            </div>
        </div>
    </section>
    <footer class="footer">
    <div class="container">
        <div class="level">
            <div class="level-start has-text-centered-mobile">
                <a class="footer-logo is-block has-mb-6" href="/hexblog/">
                
                    <img src="/hexblog/images/avatar.jpg" alt="3. SPI框架实现之旅三：实现说明" height="28">
                
                </a>
                <p class="is-size-7">
                &copy; 2020 YiHui&nbsp;
                Powered by <a href="https://hexo.io/" target="_blank">Hexo</a> & <a
                        href="https://github.com/ppoffice/hexo-theme-icarus" target="_blank">Icarus</a>
                
                </p>
            </div>
            <div class="level-end">
            
                <div class="field has-addons is-flex-center-mobile has-mt-5-mobile is-flex-wrap is-flex-middle">
                
                
                <p class="control">
                    <a class="button is-white is-large" target="_blank" title="Download on GitHub" href="https://github.com/liuyueyi">
                        
                        <i class="fab fa-github"></i>
                        
                    </a>
                </p>
                
                <p class="control">
                    <a class="button is-white is-large" target="_blank" title="Chart in Weibo" href="https://weibo.com/p/1005052169825577/home">
                        
                        <i class="fab fa-weibo"></i>
                        
                    </a>
                </p>
                
                <p class="control">
                    <a class="button is-white is-large" target="_blank" title="Frends with me" href="https://s10.mogucdn.com/mlcdn/c45406/171229_1cgld3igbelkbc70cd8af1j3809kb_150x150.jpg">
                        
                        <i class="fab fa-weixin"></i>
                        
                    </a>
                </p>
                
                </div>
            
            </div>
        </div>
    </div>
    <hr/>
    <div id="foot-pannel">
        <div class="outer">
            <div class="foot-column">
                <!--关注我们-->
                <div class="widget-wrap widget-list">
                    <h3 class="widget-title">更多平台</h3>
                    <div class="widget">
                        <ul>
                            <li>
                                <a href="//blog.hhui.top/">一灰灰Blog</a>
                            </li>
                        
                            <li>
                                <a href="//juejin.im/user/5a2a4b095188252ae93adbbf/posts">掘金</a>
                            </li>
                        
                            <li>
                                <a href="//my.oschina.net/u/566591">开源中国</a>
                            </li>
                        
                            <li>
                                <a href="//blog.csdn.net/liuyueyi25">CSDN</a>
                            </li>
                        
                            <li>
                                <a href="//www.jianshu.com/u/5902ab08e670">简书</a>
                            </li>
                        
                            <li>
                                <a href="//cloud.tencent.com/developer/column/1847">云+</a>
                            </li>
                        
                            <li>
                                <a href="//www.toutiao.com/c/user/69862071663/#mid=1579653107239950">头条</a>
                            </li>
                        
                            <li>
                                <a href="//github.com/liuyueyi">GitHub</a>
                            </li>
                        
                            <li>
                                <a href="//gitee.com/liuyueyi">Gitee</a>
                            </li>
                            
                        </ul>
                    </div>
                </div>
            </div>
            <div class="foot-column">
                <!--联系合作-->
                <div class="widget-wrap widget-list">
                    <h3 class="widget-title">一灰灰Blog</h3>
                    <div class="widget">
                        <ul>
                            
                                <li>
                                    <a href="#">QQ : 3302797840</a>
                                </li>
                            
                                <li>
                                    <a href="#">微信 : liuyueyi25</a>
                                </li>
                            
                                <li>
                                    <a href="#">邮箱 : bangzewu@126.com</a>
                                </li>
                            
                                <li>
                                    <a href="#">微博 : 一灰灰blog</a>
                                </li>
                            
                        </ul>
                    </div>
                </div>
                <div class="widget-wrap widget-list">
                    <h3 class="widget-title">友情链接</h3>
                    <div class="widget">
                        <ul>
                            
                                <span class="label">
                                    <a target="_blank" href="//zweb.hhui.top">zweb多媒体工具页</a>
                                </span>
                            
                                <span class="label">
                                    <a target="_blank" href="//mweb.hhui.top">mweb古诗选</a>
                                </span>
                            
                        </ul>
                    </div>
                </div>
            </div>
            <div class="foot-column">
                <!--友情链接-->
                <div class="widget-wrap widget-list">
                    <h3 class="widget-title">知识星球</h3>
                    <div class="widget">
                        <img style="width: 200px;" src="/hexblog/imgs/info/xingqiu.png">
                    </div>
                </div>
                
            </div>
            <div class="foot-column">
                <div class="widget-wrap widget-list">
                    <h3 class="widget-title">公众号</h3>
                    <div class="widget">
                        <img style="width: 200px;" src="/hexblog/imgs/info/wx.jpg">
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div style="padding-top:20em">
        <hr/>
        <div id="foot-info">
            <span style="margin:4px;font-size:1em">
                &copy; 2020 <a target='_blank' href='https://github.com/liuyueyi'>一灰灰Blog</a> 版权所有 | <a href="http://www.beian.miit.gov.cn" target="_blank">鄂ICP备18017282号</a>
            </span>
            <br/>
            <span style="margin:4px;font-size:1em">
                <script type="text/javascript">document.write(unescape("%3Cspan id='cnzz_stat_icon_1278691600'%3E%3C/span%3E%3Cscript src='https://s9.cnzz.com/z_stat.php%3Fid%3D1278691600%26online%3D1%26show%3Dline' type='text/javascript'%3E%3C/script%3E"));</script>
            </span>
            <span style="margin:1em;font-size:1.4em">
                <label id="self_count_cnt"><br>本站总访量: <span class="visit_cnt">69330</span> | 总访问人次: <span class="visit_cnt">11586</span> | 恭喜您为第 <span class="visit_cnt">10840</span> 访问者</label>
            </span>
            <script src="/hexblog/js/count.js"></script>
        </div>
    </div>
</footer>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.22.2/min/moment-with-locales.min.js"></script>
<script>moment.locale("zh-CN");</script>


    
    
    
    <script src="/hexblog/js/animation.js"></script>
    

    
    
    
    <script src="https://cdn.jsdelivr.net/npm/lightgallery@1.6.8/dist/js/lightgallery.min.js" defer></script>
    <script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js" defer></script>
    <script src="/hexblog/js/gallery.js" defer></script>
    

    
    

<div id="outdated">
    <h6>Your browser is out-of-date!</h6>
    <p>Update your browser to view this website correctly. <a id="btnUpdateBrowser" href="http://outdatedbrowser.com/">Update
            my browser now </a></p>
    <p class="last"><a href="#" id="btnCloseUpdateBrowser" title="Close">&times;</a></p>
</div>
<script src="https://cdn.jsdelivr.net/npm/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js" defer></script>
<script>
    document.addEventListener("DOMContentLoaded", function () {
        outdatedBrowser({
            bgColor: '#f25648',
            color: '#ffffff',
            lowerThan: 'flex'
        });
    });
</script>


    
    
<script src="https://cdn.jsdelivr.net/npm/mathjax@2.7.5/unpacked/MathJax.js?config=TeX-MML-AM_CHTML" defer></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
    MathJax.Hub.Config({
        'HTML-CSS': {
            matchFontHeight: false
        },
        SVG: {
            matchFontHeight: false
        },
        CommonHTML: {
            matchFontHeight: false
        },
        tex2jax: {
            inlineMath: [
                ['$','$'],
                ['\\(','\\)']
            ]
        }
    });
});
</script>

    
    

<a id="back-to-top" title="回到顶端" href="javascript:;">
    <i class="fas fa-chevron-up"></i>
</a>
<script src="/hexblog/js/back-to-top.js" defer></script>


    
    

    
    
    
    

    
    
    
    
    
    <script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.4/dist/clipboard.min.js" defer></script>
    <script src="/hexblog/js/clipboard.js" defer></script>
    

    
    
    


<script src="/hexblog/js/main.js" defer></script>

    
    <div class="searchbox ins-search">
    <div class="searchbox-container ins-search-container">
        <div class="searchbox-input-wrapper">
            <input type="text" class="searchbox-input ins-search-input" placeholder="想要查找什么..." />
            <span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="searchbox-result-wrapper ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: '文章',
                PAGES: '页面',
                CATEGORIES: '分类',
                TAGS: '标签',
                UNTITLED: '(无标题)',
            },
            CONTENT_URL: '/hexblog/content.json',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>
<script src="/hexblog/js/insight.js" defer></script>
<link rel="stylesheet" href="/hexblog/css/search.css">
<link rel="stylesheet" href="/hexblog/css/insight.css">
    
</body>
</html>